package com.app.utils.base.http;

import com.app.utils.base.j2se.Logger;
import com.app.utils.base.j2se.StringHandler;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/**
 * 请求处理工具
* @author 王伟
*
 */
public class RequestHandler {
	
	/**
	 * multipart的处理工厂和处理类
	 */
	private static ServletFileUpload upload;
	private static DiskFileItemFactory factory;

	/**
	 * 读取客户机IP
	 */
	public static String getIP(HttpServletRequest request){
		String ip = request.getHeader("x-forwarded-for");
		if (StringHandler.isNotEmpty(ip)) {
			String[] ips = ip.replace(" ", "").split(",");
			if (ips.length >= 1) {
				ip = StringHandler.isIp(ips[0])?ips[0]:null;
			}
		}
		if(StringHandler.isEmpty(ip)){
			ip = request.getHeader("X-Forwarded-For");
			if (StringHandler.isNotEmpty(ip)) {
				String[] ips = ip.replace(" ", "").split(",");
				if (ips.length >= 1) {
					ip = StringHandler.isIp(ips[0])?ips[0]:null;
				}
			}
		}
		if(StringHandler.isEmpty(ip)){
			ip = request.getHeader("X-Real-IP");
			if (StringHandler.isNotEmpty(ip)) {
				String[] ips = ip.replace(" ", "").split(",");
				if (ips.length >= 1) {
					ip = StringHandler.isIp(ips[0])?ips[0]:null;
				}
			}
		}
	    if(StringHandler.isEmpty(ip)) {  
	        ip = request.getHeader("Proxy-Client-IP");  
	        if (StringHandler.isNotEmpty(ip)) {
				String[] ips = ip.replace(" ", "").split(",");
				if (ips.length >= 1) {
					ip = StringHandler.isIp(ips[0])?ips[0]:null;
				}
			}
	    }
	    if(StringHandler.isEmpty(ip)) {  
	        ip = request.getHeader("WL-Proxy-Client-IP");
	        if (StringHandler.isNotEmpty(ip)) {
				String[] ips = ip.replace(" ", "").split(",");
				if (ips.length >= 1) {
					ip = StringHandler.isIp(ips[0])?ips[0]:null;
				}
			}
	    }
	    if(StringHandler.isEmpty(ip)) {  
	        ip = request.getRemoteAddr();  
	    }
	    return ip;
	}
	
	/**
	 * 获取请求中所有参数
	 * <br>1.获取常规请求 parameters are contained in the query string or posted form data.
	 * <br>2.获取请求流中xml类型请求参数
	 * <br>3.获取请求流中multipart类型请求参数
	 * <br>4.获取请求流中json类型请求参数
	 */
	public static Map<String,String> params(HttpServletRequest request){
		//获取常规请求中的参数
		Map<String,String> params = params4Con(request);
		//请求流中xml类型请求参数
//		Map<String,String> xml = params4Xml(request);
//		if(!StringHandler.isEmpty(xml)){
//			params.putAll(xml);
//		}
		//表单中文件请求参数
		Map<String,String> multipart = params4Multipart(request);
		if(!StringHandler.isEmpty(multipart)){
			params.putAll(multipart);
		}
		//解析json格式数据
		Map<String,String> jsonParam = params4Json(request);
		if(!StringHandler.isEmpty(jsonParam)){
			params.putAll(jsonParam);
		}
		return params;
	}
	
	/**
	 * 获取请求中所有参数
	 * <br>1.获取常规请求 parameters are contained in the query string or posted form data.
	 * <br>2.获取请求流中xml类型请求参数
	 * <br>3.获取请求流中multipart类型请求参数
	 * <br>4.获取请求cookies中特殊请求参数[兼容web端直接存放cookies的情况]
	 */
	public static Map<String,String> params(Map<String, String> keys, HttpServletRequest request){
		//获取常规请求中/请求流中xml类型/表单中文件/的参数
		Map<String,String> params = params(request);
		//cookies中特殊请求参数
		Map<String,String> cookies = params4Cookies(keys, request);
		if(!StringHandler.isEmpty(cookies)){
			params.putAll(cookies);
		}
		return params;
	}
	
	/**
	 * 获得常规请求中所有请求参数
	 * <br>常规：parameters are contained in the query string or posted form data.
	 */
	public static Map<String,String> params4Con(HttpServletRequest request){
		Map<String,String> params = new HashMap<String,String>();
		Map<String,String[]> requestParams = request.getParameterMap();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			//乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
			params.put(name, valueStr);
		}
		return params;
	}
	
	/**
	 * 获取请求流中xml类型请求参数
	 */
//	public static Map<String,String> params4Xml(HttpServletRequest request){
//		//获取request请求的contentType
//		String contentType = request.getContentType();
//		//若请求的类型不为xml，返回空
//		if (StringHandler.isEmpty(contentType) || !contentType.toLowerCase(Locale.ENGLISH).contains("xml")) {
//			return null;
//		}
//		//防止表单请求的分隔符包含xml的情况
//		if(contentType.toLowerCase(Locale.ENGLISH).startsWith("multipart/")){
//			return null;
//		}
//		String xml = "";
//		//若请求的类型为xml，则对xml进行解析
//		try {
//			InputStreamReader isr = new InputStreamReader(request.getInputStream());
//			xml = Streams.readAndClose(isr);
//			log.infof("xml : %s %s %s", request.getSession().getId().toLowerCase(), request.getRequestURI(), xml);
//			return XmlHandler.decodeXml(xml);
//		} catch (Exception e) {
//			try {
//				Map<String,String> map = new HashMap<>();
//				Json.fromJson(xml);
//				map.put("jsonParam", xml);
//				return map;
//			} catch (Exception e2) {
//				log.errorLoc("请求助手解析XML中Json", null, e2);
//			}
//			log.errorLoc("请求助手解析XML", null, e);
//		}
//		return null;
//	}
	
	/**
	 * 读取multipart请求中的参数和文件 文件放到request中
	 */
	@SuppressWarnings("unchecked")
	public static Map<String,String> params4Multipart(HttpServletRequest request){
		//获取request请求的contentType
		String contentType = request.getContentType();
		//若请求的类型不为multipart，则返回空
		if(StringHandler.isEmpty(contentType) || !contentType.toLowerCase(Locale.ENGLISH).startsWith("multipart/")){
			return null;
		}
		//创建处理工厂和类
		if(null == upload){
			factory = new DiskFileItemFactory();
			upload = new ServletFileUpload(factory);
			upload.setHeaderEncoding(request.getCharacterEncoding()); 
		}
		//若请求的类型为multipart，则对xml进行解析
		Map<String, String> params = null;
		try {
			List<FileItem> items = upload.parseRequest(request);
			params = new HashMap<>();
			for (FileItem item : items) {
				//isFormField为true，表示这不是文件上传表单域 
				if(item.isFormField()){ 
					params.put(item.getFieldName(), item.getString(request.getCharacterEncoding()));
				}else{
					request.setAttribute(item.getFieldName(), item);
					Logger.info("%s file %s %s bytes", request.getSession().getId().toLowerCase(), item.getName(), item.getSize());
				}
			}
			Logger.info("multipart : %s %s %s", request.getSession().getId().toLowerCase(), request.getRequestURI(), params);
		} catch (Exception e) {
			Logger.error("请求助手解析multipart", e);
		}
		request.setAttribute("UploadParams", params);
		return params;
	}
	
	/**
	 * 获取请求Cookies中特殊请求参数
	 * @param keys Cookie中关心的key集合 key=key value=key的别名
	 */
	public static Map<String,String> params4Cookies(Map<String, String> keys, HttpServletRequest request){
		//keys为空
		if(StringHandler.isEmpty(keys)){
			return null;
		}
		//cookies为空
		if(null == request.getCookies() || request.getCookies().length == 0){
			return null;
		}
		//遍历cookies获取对应值
		Map<String,String> map = null;
		for (Cookie cookie : request.getCookies()) {
			if(null == cookie){
				continue;
			}
			String keyPair = cookie.getName();
			if (!keys.containsKey(keyPair)) {
				continue;
			}
			if(null == map){
				map = new HashMap<String, String>();
			}
			map.put(keys.get(keyPair), cookie.getValue());
		}
		return map;
	}
	
	/**
	 * 通过配置的请求有效参数列表 从请求中获取所有参数值
	 * @param params 请求有效参数列表 多个请求参数用","分隔 如：roomId,type
	 * @return 如果都没有获取到值 返回null
	 */
	public static Map<String, String> get(String params, HttpServletRequest request){
		String value;
		Map<String, String> map = null;
		String[] paramss = params.split(",");
		for(String name : paramss){
			value = request.getParameter(name);
			if(StringHandler.isEmpty(value)){
				continue;
			}
			if(map == null){
				map = new HashMap<String, String>();
			}
			map.put(name, value);
		}
		return map;
	}
	
	/**
	 * 请求是否为ajax
	 * @return true=是ajax
	 */
	public static boolean isAjax(HttpServletRequest request){
		String requestType = request.getHeader("X-Requested-With");
		return requestType != null && requestType.equals("XMLHttpRequest");
	}
	
	/**
	 * request解析jsonshuju
	 * @param request
	 * @return
	 */
	public static Map<String, String> params4Json(HttpServletRequest request) {
		// 获取request请求的contentType
		String contentType = request.getContentType();
		// 若请求的类型不为json，则返回空
		if (StringHandler.isEmpty(contentType) || !contentType.toLowerCase(Locale.ENGLISH).contains("/json")) {
			return null;
		}
		StringBuilder stringBuilder = new StringBuilder();
		BufferedReader bufferedReader = null;
		Map<String, String> map = null;
		try {
			InputStream inputStream = request.getInputStream();
			map = new HashMap<>();
			if (inputStream != null) {
				bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
				char[] charBuffer = new char[128];
				int bytesRead = -1;
				while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
					stringBuilder.append(charBuffer, 0, bytesRead);
				}
			} else {
				stringBuilder.append("");
			}
		} catch (IOException ex) {
			Logger.error("请求助手解析json", ex);
		} finally {
			if (bufferedReader != null) {
				try {
					bufferedReader.close();
				} catch (IOException ex) {
					Logger.error("请求助手解析json关闭IO", ex);
				}
			}
		}
		map.put("jsonParam", stringBuilder.toString());
		return map;
	}

}
